﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using System.Xml;
using P;

namespace IMLibrary
{

	/// <summary>
	/// 消息对像加工厂
	/// </summary>
	public class XMLFactory
	{
		private static System.Text.UTF8Encoding utf8 = new UTF8Encoding();

		private static byte[] NullBytes = new byte[1];

		/// <summary>
		/// 返回对像序列化二进制数组
		/// </summary>
		/// <param name="e"></param>
		/// <returns></returns>
		public static byte[] ConvertToArray(object e)
		{
			string s = CreateXMLMsg(e);
			if (s != null)
				return System.Text.Encoding.UTF8.GetBytes(s);
			else
				return NullBytes;
		}

		#region 创建XML消息
		/// <summary>
		/// 创建XML消息
		/// </summary>
		/// <param name="e">Element</param>
		/// <returns></returns>
		public static string CreateXMLMsg(object e)
		{
			if (e == null) return null;
			if (e is P.Message)
			{
				var msg = ( P.Message)e;
				///压缩传输数据
				if (msg.FontName == "宋体") msg.FontName = null;
				if (msg.FontSize == 9) msg.FontSize = 0;
				if (msg.FontColor == -16777216) msg.FontColor = 0;
			}


			MemoryStream fileStream = new MemoryStream();
			XmlTextWriter textWriter = new XmlTextWriter(fileStream, utf8);
			textWriter.WriteStartDocument();
			try
			{
				textWriter.WriteStartElement(e.GetType().ToString());
				PropertyInfo[] propertys = e.GetType().GetProperties();
				foreach (PropertyInfo p in propertys)
				{
					if (p.PropertyType == typeof(String) || p.PropertyType == typeof(char)
						|| p.PropertyType == typeof(bool) || p.PropertyType.IsEnum)
					{
						if (p.GetValue(e, null) != null)
						{
							var value = p.GetValue(e, null).ToString();
							if (value != string.Empty && value != "" && value != "False")
								textWriter.WriteAttributeString(p.Name, value);
						}
					}
					if( 
						p.PropertyType == typeof(int)
						|| p.PropertyType == typeof(Single)
						|| p.PropertyType == typeof(float)
						|| p.PropertyType == typeof(byte)
						|| p.PropertyType == typeof(short)
						|| p.PropertyType == typeof(long)
						|| p.PropertyType == typeof(sbyte)
						|| p.PropertyType == typeof(ushort)
						|| p.PropertyType == typeof(uint)
						|| p.PropertyType == typeof(ulong)
						|| p.PropertyType == typeof(double)
						|| p.PropertyType == typeof(decimal)
					)
					{
						if (p.GetValue(e, null) != null)
						{
							var value =p.GetValue(e, null).ToString();
							if (value != "0")
								textWriter.WriteAttributeString(p.Name, value);
						}
					}
					else if (p.PropertyType == typeof(byte[]))
					{
						if (p.GetValue(e, null) != null)
						{
							textWriter.WriteAttributeString(p.Name, Convert.ToBase64String((byte[])p.GetValue(e, null)));
						}
					}
					else if (p.PropertyType == typeof(List<object>))
					{
						foreach (Object Obj in (p.GetValue(e, null) as List<object>))
						{
							textWriter.WriteStartElement(Obj.GetType().ToString());
							propertys = Obj.GetType().GetProperties();
							foreach (PropertyInfo ps in propertys)
							{
								if (ps.PropertyType == typeof(String) || ps.PropertyType == typeof(char)
									|| ps.PropertyType == typeof(bool) || ps.PropertyType.IsEnum)
								{
									if (ps.GetValue(Obj, null) != null)
									{
										var value = ps.GetValue(Obj, null).ToString();
										if (value != string.Empty && value != "" && value != "False")
											textWriter.WriteAttributeString(ps.Name, value);
									}
								}
								if (
									ps.PropertyType == typeof(int)
									|| ps.PropertyType == typeof(Single)
									|| ps.PropertyType == typeof(float)
									|| ps.PropertyType == typeof(byte)
									|| ps.PropertyType == typeof(short)
									|| ps.PropertyType == typeof(long)
									|| ps.PropertyType == typeof(sbyte)
									|| ps.PropertyType == typeof(ushort)
									|| ps.PropertyType == typeof(uint)
									|| ps.PropertyType == typeof(ulong)
									|| ps.PropertyType == typeof(double)
									|| ps.PropertyType == typeof(decimal)
								)
								{
									if (ps.GetValue(Obj, null) != null)
									{
										var value = ps.GetValue(Obj, null).ToString();
										if (value != "0")
											textWriter.WriteAttributeString(ps.Name, value);
									}
								}
								else if (ps.PropertyType == typeof(byte[]))
								{
									if (ps.GetValue(Obj, null) != null)
									{
										textWriter.WriteAttributeString(ps.Name, Convert.ToBase64String((byte[])ps.GetValue(Obj, null)));
									}
								}
							}
							textWriter.WriteEndElement();
						}
					}
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Source + ex.Message);
			}
			textWriter.WriteEndElement();
			textWriter.WriteEndDocument();
			textWriter.Close();

			return System.Text.UTF8Encoding.UTF8.GetString(fileStream.ToArray()).Trim().Replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "");
		}
		#endregion

		#region 从XML中获取一个对像
		/// <summary>
		/// 从XML中获取一个对像 
		/// </summary>
		public static object CreateObject(string xmlStr)
		{ 
			if (xmlStr == null) return null;
			xmlStr = xmlStr.Trim();
			if (xmlStr == "") return null;

			object obj = null;
			try
			{
				XmlReader xmlReader = XmlTextReader.Create(new StringReader(xmlStr));
				if (xmlReader.Read() && xmlReader.NodeType == XmlNodeType.Element)
				{
					Type ctype =Assembly.GetExecutingAssembly().GetType(xmlReader.Name);
					obj = System.Activator.CreateInstance(ctype);
					if (obj == null) return null;

					PropertyInfo[] propertys = obj.GetType().GetProperties();
					if (xmlReader.HasAttributes)
						foreach (PropertyInfo p in propertys)
						{
							if (xmlReader.MoveToAttribute(p.Name))
							{
								if (p.PropertyType == typeof(String))
									p.SetValue(obj, xmlReader.ReadContentAsString(), null);
								else if (p.PropertyType == typeof(bool))
									p.SetValue(obj, bool.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(int))
									p.SetValue(obj, int.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(Single))
									p.SetValue(obj, Single.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(float))
									p.SetValue(obj, float.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType.IsEnum)
									p.SetValue(obj, System.Enum.Parse(p.PropertyType, xmlReader.ReadContentAsString(), true), null);
								else if (p.PropertyType == typeof(short))
									p.SetValue(obj, short.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(long))
									p.SetValue(obj, long.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(byte))
									p.SetValue(obj, byte.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(sbyte))
									p.SetValue(obj, sbyte.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(ushort))
									p.SetValue(obj, ushort.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(uint))
									p.SetValue(obj, uint.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(ulong))
									p.SetValue(obj, ulong.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(double))
									p.SetValue(obj, double.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(decimal))
									p.SetValue(obj, decimal.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(char))
									p.SetValue(obj, char.Parse(xmlReader.ReadContentAsString()), null);
								else if (p.PropertyType == typeof(byte[]))
									p.SetValue(obj, Convert.FromBase64String(xmlReader.ReadContentAsString()), null);
							}
						}
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Source + ex.Message);
			}
			return obj;
		}
		#endregion

		#region 从XML中获取所需要的对像(对像在返回值集合中获取)
		/// <summary>
		/// 从XML中获取所需要的对像(对像在返回值集合中获取)
		/// </summary>
		public static List<Object> CreateObjects(string xmlStr)
		{ 
			if (xmlStr == null) return null;
			xmlStr = xmlStr.Trim();
			if (xmlStr == "") return null;

			List<Object> objList = null;
			try
			{
				XmlReader xmlReader = XmlTextReader.Create(new StringReader(xmlStr));               
				while (xmlReader.Read())
					if (xmlReader.NodeType == XmlNodeType.Element)
					{
						Type ctype = Assembly.GetExecutingAssembly().GetType(xmlReader.Name);
						object obj = System.Activator.CreateInstance(ctype);
						PropertyInfo[] propertys = obj.GetType().GetProperties();
						if (xmlReader.HasAttributes)
							foreach (PropertyInfo p in propertys)
							{
								if (xmlReader.MoveToAttribute(p.Name))
									try
								{
									if (p.PropertyType == typeof(String))
										p.SetValue(obj, xmlReader.ReadContentAsString(), null);
									else if (p.PropertyType == typeof(bool))
										p.SetValue(obj, bool.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(int))
										p.SetValue(obj, int.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(Single))
										p.SetValue(obj, Single.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(float))
										p.SetValue(obj, float.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType.IsEnum)
										p.SetValue(obj, System.Enum.Parse(p.PropertyType, xmlReader.ReadContentAsString(), true), null);
									else if (p.PropertyType == typeof(short))
										p.SetValue(obj, short.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(long))
										p.SetValue(obj, long.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(byte))
										p.SetValue(obj, byte.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(sbyte))
										p.SetValue(obj, sbyte.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(ushort))
										p.SetValue(obj, ushort.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(uint))
										p.SetValue(obj, uint.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(ulong))
										p.SetValue(obj, ulong.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(double))
										p.SetValue(obj, double.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(decimal))
										p.SetValue(obj, decimal.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(char))
										p.SetValue(obj, char.Parse(xmlReader.ReadContentAsString()), null);
									else if (p.PropertyType == typeof(byte[]))
										p.SetValue(obj, Convert.FromBase64String(xmlReader.ReadContentAsString()), null);
								}
								catch (Exception ex)
								{
									Console.WriteLine(ex.Source + ex.Message);
								}
							}
						if (objList == null)
							objList = new List<object>();

						objList.Add(obj);
					}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Source + ex.Message);
			}
			return objList;
		}
		#endregion
	}
}
